﻿#pragma once

#include <zmq/zmsg.hpp>
#include <stdint.h>
//#include <unistd.h>
#include "qt_windows.h"
#include <vector>
#include <atomic>
#include <iomanip>
#include <sstream>

using namespace std;

#define REQUEST_TIMEOUT 2500 // 非心跳检测下请求间隔时间
#define REQUEST_RETRIES 3    // 请求间隔次数

#define HEARTBEAT_LIVENESS 3    //  活动检测 如果等于0则认为不活动（原作者建议为3-5）
#define HEARTBEAT_INTERVAL 1000 //  心跳检测间隔时间（毫秒）
#define INTERVAL_INIT 1000      //  初始化重连时间
#define INTERVAL_MAX 32000      //  最长重连时间

//客户端标识结构体
typedef struct
{
    std::string identity; // 客户端标识
    int64_t expiry;       // 过期时间
} worker_t;

/**
 * @param socket 当前连接的套接字
 * @param msg zmq消息
 * @param queue 当前连接的队列信息
 * @param identity 当前消息发送者的编号
 * @param message 消息
 */
typedef void (*QueueMsgCallBack)(zmq::socket_t *socket, zmsg &msg, std::vector<worker_t> &queue, std::string &identity,const char *message);
/**
 * @param queue 服务器连接的客户端队列
 * @param identity 新连接的客户端
 */
typedef void (*QueueAppendCallBack)(std::vector<worker_t> &queue, std::string &identity);
/**
 * @param queue 服务器连接的客户端队列
 * @param identity 新断开的客户端
 */
typedef void (*QueueQuitCallBack)(std::vector<worker_t> &queue, std::string &identity);
/**
 * @param socket 当前连接的套接字
 * @param msg zmq 消息
 * @param identity 当前消息发送者的编号
 * @param message 消息
 */
typedef void (*SimpleMsgCallBack)(zmq::socket_t *socket, zmsg &msg, std::string &identity,const char *message);
/**
 * @param identity 新连接的客户端
 */
typedef void (*SimpleAppendCallBack)(std::string &identity);
/**
 * @param identity 新断开的客户端
 */
typedef void (*SimpleQuitCallBack)(std::string &identity);
/**
 * 订阅消息回调
 */
typedef void (*SubMsgCallBack)(const char *message,const char *topic);

/**
 * 请求回应模式：发送请求回调（收到回复的消息）
 */
typedef void (*ReqMsgCallBack)(const char *message);

/**
 * 请求回应模式：收到请求回调（收到请求的消息）
 */
typedef void (*RepMsgCallBack)(const char *message);


/**
 * 队列客户端 会一直保持连接 服务器断开会一直重试
 * @param url 服务器地址
 * @param identity 客户端标识符（唯一）
 * @param msg 消息返回函数
 */
int quence_client(std::string &url, std::string &identity, SimpleMsgCallBack msgCallBack);
/**
 * 基础连接客户端 会多次重连 失败后会返回-1 发送成功之后返回0
 * @param url 服务器地址
 * @param identity 客户端标识符（唯一）
 * @param msg 消息返回函数
 */
int simple_client(std::string &url, std::string &identity, SimpleMsgCallBack msgCallBack,std::string& message);
/**
 * 队列模式 可对多个客户端进行心跳检测
 * @param queue 客户端队列
 * @param port 服务器监测端口
 * @param msgCallBack 服务器端消息处理函数
 * @param cacb 客户端进入回调
 * @param cqcb 客户端退出回调
 */
int quence_service(int port, QueueMsgCallBack msgCallBack, QueueAppendCallBack cacb,QueueQuitCallBack cqcb);
/**
 * 点对点 指定某个客户端连接
 * @param queue 客户端队列
 * @param port 服务器监测端口
 * @param msgCallBack 服务器端消息处理函数
 * @param cacb 客户端进入回调
 * @param cqcb 客户端退出回调
 */
int point_service(int port, string &clientId, SimpleMsgCallBack msgCallBack, SimpleAppendCallBack cacb, SimpleQuitCallBack cqcb);
/**
 * 基础模式 无心跳检测 只是循环接收消息
 * @param port 监听端口
 * @param simpleMsgCallBack 消息接收回调
 */
int simple_service(int port, SimpleMsgCallBack msgCallBack);
/**
 * 在当前已连接的套接字上发送消息
 */
int pub_on_con_socket(zmq::socket_t *socket,zmsg &msg,string& identity,string& message);
/**
 * 发布订阅模式 发布
 */
int pub_zmq(string& message,string &url,string& topic);
/**
 * 发布订阅模式 订阅
 */
int sub_zmq(string& url, SubMsgCallBack smcb,string& topic);

/**
 * 请求回应模式 请求
 * @brief req_zmq
 * @param url
 * @param msg
 * @param cb
 * @return
 */
int req_zmq(string& url,string& msg, ReqMsgCallBack cb);

/**
 * 请求回应模式 应答
 * @brief rep_zmq
 * @param url
 * @param cb
 * @return
 */

int rep_zmq(string& url,RepMsgCallBack cb);


static zmq::socket_t * s_client_socket (zmq::context_t & context,string &url);
